////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 
// 
// This file is part of the Microsoft .NET Micro Framework Porting Kit Code Samples and is unsupported. 
// Copyright (C) Microsoft Corporation. All rights reserved. Use of this sample source code is subject to 
// the terms of the Microsoft license agreement under which you licensed this sample source code. 
// 
// THIS SAMPLE CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 
// INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// 
// 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef _AT91__TIMER_H_1
#define _AT91__TIMER_H_1   1

//#include "..\AT91_AIC\AT91_AIC.h"

//////////////////////////////////////////////////////////////////////////////
// AT91 Timer Channel
//

struct AT91_TC {
    volatile UINT32     TC_CCR;    // Channel Control Register
    volatile UINT32     TC_CMR;    // Channel Mode Register (Capture Mode / Waveform Mode)
    volatile UINT32     Reserved0[2];  
    volatile UINT32     TC_CV;     // Counter Value
    volatile UINT32     TC_RA;     // Register A
    volatile UINT32     TC_RB;     // Register B
    volatile UINT32     TC_RC;     // Register C
    volatile UINT32     TC_SR;     // Status Register
    volatile UINT32     TC_IER;    // Interrupt Enable Register
    volatile UINT32     TC_IDR;    // Interrupt Disable Register
    volatile UINT32     TC_IMR;    // Interrupt Mask Register
};

// -------- TC_CCR : (TC Offset: 0x0) TC Channel Control Register -------- 
#define AT91C_TC_CLKEN        (0x1 <<  0) // (TC) Counter Clock Enable Command
#define AT91C_TC_CLKDIS       (0x1 <<  1) // (TC) Counter Clock Disable Command
#define AT91C_TC_SWTRG        (0x1 <<  2) // (TC) Software Trigger Command

// -------- TC_CMR : (TC Offset: 0x4) TC Channel Mode Register: Capture Mode / Waveform Mode -------- 
#define AT91C_TC_CLKS         (0x7 <<  0) // (TC) Clock Selection
#define     AT91C_TC_CLKS_TIMER_DIV1_CLOCK     (0x0) // (TC) Clock selected: TIMER_DIV1_CLOCK
#define     AT91C_TC_CLKS_TIMER_DIV2_CLOCK     (0x1) // (TC) Clock selected: TIMER_DIV2_CLOCK
#define     AT91C_TC_CLKS_TIMER_DIV3_CLOCK     (0x2) // (TC) Clock selected: TIMER_DIV3_CLOCK
#define     AT91C_TC_CLKS_TIMER_DIV4_CLOCK     (0x3) // (TC) Clock selected: TIMER_DIV4_CLOCK
#define     AT91C_TC_CLKS_TIMER_DIV5_CLOCK     (0x4) // (TC) Clock selected: TIMER_DIV5_CLOCK
#define     AT91C_TC_CLKS_XC0                  (0x5) // (TC) Clock selected: XC0
#define     AT91C_TC_CLKS_XC1                  (0x6) // (TC) Clock selected: XC1
#define     AT91C_TC_CLKS_XC2                  (0x7) // (TC) Clock selected: XC2
#define AT91C_TC_CLKI         (0x1 <<  3) // (TC) Clock Invert
#define AT91C_TC_BURST        (0x3 <<  4) // (TC) Burst Signal Selection
#define     AT91C_TC_BURST_NONE                 (0x0 <<  4) // (TC) The clock is not gated by an external signal
#define     AT91C_TC_BURST_XC0                  (0x1 <<  4) // (TC) XC0 is ANDed with the selected clock
#define     AT91C_TC_BURST_XC1                  (0x2 <<  4) // (TC) XC1 is ANDed with the selected clock
#define     AT91C_TC_BURST_XC2                  (0x3 <<  4) // (TC) XC2 is ANDed with the selected clock
#define AT91C_TC_CPCSTOP      (0x1 <<  6) // (TC) Counter Clock Stopped with RC Compare
#define AT91C_TC_LDBSTOP      (0x1 <<  6) // (TC) Counter Clock Stopped with RB Loading
#define AT91C_TC_CPCDIS       (0x1 <<  7) // (TC) Counter Clock Disable with RC Compare
#define AT91C_TC_LDBDIS       (0x1 <<  7) // (TC) Counter Clock Disabled with RB Loading
#define AT91C_TC_ETRGEDG      (0x3 <<  8) // (TC) External Trigger Edge Selection
#define     AT91C_TC_ETRGEDG_NONE                 (0x0 <<  8) // (TC) Edge: None
#define     AT91C_TC_ETRGEDG_RISING               (0x1 <<  8) // (TC) Edge: rising edge
#define     AT91C_TC_ETRGEDG_FALLING              (0x2 <<  8) // (TC) Edge: falling edge
#define     AT91C_TC_ETRGEDG_BOTH                 (0x3 <<  8) // (TC) Edge: each edge
#define AT91C_TC_EEVTEDG      (0x3 <<  8) // (TC) External Event Edge Selection
#define     AT91C_TC_EEVTEDG_NONE                 (0x0 <<  8) // (TC) Edge: None
#define     AT91C_TC_EEVTEDG_RISING               (0x1 <<  8) // (TC) Edge: rising edge
#define     AT91C_TC_EEVTEDG_FALLING              (0x2 <<  8) // (TC) Edge: falling edge
#define     AT91C_TC_EEVTEDG_BOTH                 (0x3 <<  8) // (TC) Edge: each edge
#define AT91C_TC_EEVT         (0x3 << 10) // (TC) External Event  Selection
#define     AT91C_TC_EEVT_TIOB                 (0x0 << 10) // (TC) Signal selected as external event: TIOB TIOB direction: input
#define     AT91C_TC_EEVT_XC0                  (0x1 << 10) // (TC) Signal selected as external event: XC0 TIOB direction: output
#define     AT91C_TC_EEVT_XC1                  (0x2 << 10) // (TC) Signal selected as external event: XC1 TIOB direction: output
#define     AT91C_TC_EEVT_XC2                  (0x3 << 10) // (TC) Signal selected as external event: XC2 TIOB direction: output
#define AT91C_TC_ABETRG       (0x1 << 10) // (TC) TIOA or TIOB External Trigger Selection
#define AT91C_TC_ENETRG       (0x1 << 12) // (TC) External Event Trigger enable
#define AT91C_TC_WAVESEL      (0x3 << 13) // (TC) Waveform  Selection
#define     AT91C_TC_WAVESEL_UP                   (0x0 << 13) // (TC) UP mode without atomatic trigger on RC Compare
#define     AT91C_TC_WAVESEL_UPDOWN               (0x1 << 13) // (TC) UPDOWN mode without automatic trigger on RC Compare
#define     AT91C_TC_WAVESEL_UP_AUTO              (0x2 << 13) // (TC) UP mode with automatic trigger on RC Compare
#define     AT91C_TC_WAVESEL_UPDOWN_AUTO          (0x3 << 13) // (TC) UPDOWN mode with automatic trigger on RC Compare
#define AT91C_TC_CPCTRG       (0x1 << 14) // (TC) RC Compare Trigger Enable
#define AT91C_TC_WAVE         (0x1 << 15) // (TC) 
#define AT91C_TC_ACPA         (0x3 << 16) // (TC) RA Compare Effect on TIOA
#define     AT91C_TC_ACPA_NONE                 (0x0 << 16) // (TC) Effect: none
#define     AT91C_TC_ACPA_SET                  (0x1 << 16) // (TC) Effect: set
#define     AT91C_TC_ACPA_CLEAR                (0x2 << 16) // (TC) Effect: clear
#define     AT91C_TC_ACPA_TOGGLE               (0x3 << 16) // (TC) Effect: toggle
#define AT91C_TC_LDRA         (0x3 << 16) // (TC) RA Loading Selection
#define     AT91C_TC_LDRA_NONE                 (0x0 << 16) // (TC) Edge: None
#define     AT91C_TC_LDRA_RISING               (0x1 << 16) // (TC) Edge: rising edge of TIOA
#define     AT91C_TC_LDRA_FALLING              (0x2 << 16) // (TC) Edge: falling edge of TIOA
#define     AT91C_TC_LDRA_BOTH                 (0x3 << 16) // (TC) Edge: each edge of TIOA
#define AT91C_TC_ACPC         (0x3 << 18) // (TC) RC Compare Effect on TIOA
#define     AT91C_TC_ACPC_NONE                 (0x0 << 18) // (TC) Effect: none
#define     AT91C_TC_ACPC_SET                  (0x1 << 18) // (TC) Effect: set
#define     AT91C_TC_ACPC_CLEAR                (0x2 << 18) // (TC) Effect: clear
#define     AT91C_TC_ACPC_TOGGLE               (0x3 << 18) // (TC) Effect: toggle
#define AT91C_TC_LDRB         (0x3 << 18) // (TC) RB Loading Selection
#define     AT91C_TC_LDRB_NONE                 (0x0 << 18) // (TC) Edge: None
#define     AT91C_TC_LDRB_RISING               (0x1 << 18) // (TC) Edge: rising edge of TIOA
#define     AT91C_TC_LDRB_FALLING              (0x2 << 18) // (TC) Edge: falling edge of TIOA
#define     AT91C_TC_LDRB_BOTH                 (0x3 << 18) // (TC) Edge: each edge of TIOA
#define AT91C_TC_AEEVT        (0x3 << 20) // (TC) External Event Effect on TIOA
#define     AT91C_TC_AEEVT_NONE                 (0x0 << 20) // (TC) Effect: none
#define     AT91C_TC_AEEVT_SET                  (0x1 << 20) // (TC) Effect: set
#define     AT91C_TC_AEEVT_CLEAR                (0x2 << 20) // (TC) Effect: clear
#define     AT91C_TC_AEEVT_TOGGLE               (0x3 << 20) // (TC) Effect: toggle
#define AT91C_TC_ASWTRG       (0x3 << 22) // (TC) Software Trigger Effect on TIOA
#define     AT91C_TC_ASWTRG_NONE                 (0x0 << 22) // (TC) Effect: none
#define     AT91C_TC_ASWTRG_SET                  (0x1 << 22) // (TC) Effect: set
#define     AT91C_TC_ASWTRG_CLEAR                (0x2 << 22) // (TC) Effect: clear
#define     AT91C_TC_ASWTRG_TOGGLE               (0x3 << 22) // (TC) Effect: toggle
#define AT91C_TC_BCPB         (0x3 << 24) // (TC) RB Compare Effect on TIOB
#define     AT91C_TC_BCPB_NONE                 (0x0 << 24) // (TC) Effect: none
#define     AT91C_TC_BCPB_SET                  (0x1 << 24) // (TC) Effect: set
#define     AT91C_TC_BCPB_CLEAR                (0x2 << 24) // (TC) Effect: clear
#define     AT91C_TC_BCPB_TOGGLE               (0x3 << 24) // (TC) Effect: toggle
#define AT91C_TC_BCPC         (0x3 << 26) // (TC) RC Compare Effect on TIOB
#define     AT91C_TC_BCPC_NONE                 (0x0 << 26) // (TC) Effect: none
#define     AT91C_TC_BCPC_SET                  (0x1 << 26) // (TC) Effect: set
#define     AT91C_TC_BCPC_CLEAR                (0x2 << 26) // (TC) Effect: clear
#define     AT91C_TC_BCPC_TOGGLE               (0x3 << 26) // (TC) Effect: toggle
#define AT91C_TC_BEEVT        (0x3 << 28) // (TC) External Event Effect on TIOB
#define     AT91C_TC_BEEVT_NONE                 (0x0 << 28) // (TC) Effect: none
#define     AT91C_TC_BEEVT_SET                  (0x1 << 28) // (TC) Effect: set
#define     AT91C_TC_BEEVT_CLEAR                (0x2 << 28) // (TC) Effect: clear
#define     AT91C_TC_BEEVT_TOGGLE               (0x3 << 28) // (TC) Effect: toggle
#define AT91C_TC_BSWTRG       (0x3 << 30) // (TC) Software Trigger Effect on TIOB
#define     AT91C_TC_BSWTRG_NONE                 (0x0 << 30) // (TC) Effect: none
#define     AT91C_TC_BSWTRG_SET                  (0x1 << 30) // (TC) Effect: set
#define     AT91C_TC_BSWTRG_CLEAR                (0x2 << 30) // (TC) Effect: clear
#define     AT91C_TC_BSWTRG_TOGGLE               (0x3 << 30) // (TC) Effect: toggle

// -------- TC_IER : (TC Offset: 0x24) TC Channel Interrupt Enable Register -------- 
// -------- TC_IDR : (TC Offset: 0x28) TC Channel Interrupt Disable Register -------- 
// -------- TC_IMR : (TC Offset: 0x2c) TC Channel Interrupt Mask Register -------- 
// -------- TC_SR : (TC Offset: 0x20) TC Channel Status Register -------- 
#define AT91C_TC_COVFS        (0x1 <<  0) // (TC) Counter Overflow
#define AT91C_TC_LOVRS        (0x1 <<  1) // (TC) Load Overrun
#define AT91C_TC_CPAS         (0x1 <<  2) // (TC) RA Compare
#define AT91C_TC_CPBS         (0x1 <<  3) // (TC) RB Compare
#define AT91C_TC_CPCS         (0x1 <<  4) // (TC) RC Compare
#define AT91C_TC_LDRAS        (0x1 <<  5) // (TC) RA Loading
#define AT91C_TC_LDRBS        (0x1 <<  6) // (TC) RB Loading
#define AT91C_TC_ETRGS        (0x1 <<  7) // (TC) External Trigger
#define AT91C_TC_CLKSTA       (0x1 << 16) // (TC) Clock Enabling
#define AT91C_TC_MTIOA        (0x1 << 17) // (TC) TIOA Mirror
#define AT91C_TC_MTIOB        (0x1 << 18) // (TC) TIOA Mirror
//
// AT91 Timer Channel
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// TIMER driver
//
struct AT91_TIMER_Driver
{
    static const UINT32 c_SystemTimer   = 0;
    static const UINT16 c_MaxTimerValue = 0xFFFF; 

    //--//

    static BOOL Initialize   ( UINT32 Timer, BOOL FreeRunning, UINT32 ClkSource, HAL_CALLBACK_FPN ISR, void* ISR_Param );
    static BOOL Uninitialize ( UINT32 Timer );
    static void ISR_TIMER( void* param );

    static void EnableCompareInterrupt( UINT32 Timer )
    {
        ASSERT(Timer < AT91_MAX_TIMER);
        struct AT91_TC *pTc = (AT91_TC *)(AT91C_BASE_TC0 + Timer*0x40);
        (void) pTc->TC_SR;
        pTc->TC_IER = AT91C_TC_CPCS;
        pTc->TC_CCR = (AT91C_TC_SWTRG  | AT91C_TC_CLKEN) ;
    }

    static void DisableCompareInterrupt( UINT32 Timer )
    {
        ASSERT(Timer < AT91_MAX_TIMER);
        struct AT91_TC *pTc = (AT91_TC *)(AT91C_BASE_TC0 + Timer*0x40);
        pTc->TC_IDR = AT91C_TC_CPCS; 
    }

    static void ForceInterrupt( UINT32 Timer )
    {
        ASSERT(Timer < AT91_MAX_TIMER);
        ASSERT_IRQ_MUST_BE_OFF();
        AT91_AIC_Driver::ForceInterrupt( AT91C_ID_TC0 + Timer );
    }

    static void SetCompare( UINT32 Timer, UINT16 Compare )
    {
        ASSERT(Timer < AT91_MAX_TIMER);
        struct AT91_TC *pTc = (AT91_TC *)(AT91C_BASE_TC0 + Timer*0x40);
        pTc->TC_RC = Compare;
    }

    static UINT16 ReadCounter( UINT32 Timer )
    {
        ASSERT(Timer < AT91_MAX_TIMER);
        struct AT91_TC *pTc = (AT91_TC *)(AT91C_BASE_TC0 + Timer*0x40);
        return    pTc->TC_CV;
    }

    static BOOL DidTimerOverFlow( UINT32 Timer )
    {
        ASSERT(Timer < AT91_MAX_TIMER);
        struct AT91_TC *pTc = (AT91_TC *)(AT91C_BASE_TC0 + Timer*0x40);
        
        return (pTc->TC_SR & AT91C_TC_COVFS) != 0;        
    }

//--//

private:
    struct Descriptors
    {
        HAL_CALLBACK_FPN isr;
        void* arg;
        BOOL configured;
    };
    Descriptors m_descriptors[AT91_MAX_TIMER];

   
};

extern AT91_TIMER_Driver g_AT91_TIMER_Driver;
//
// TIMER driver
//////////////////////////////////////////////////////////////////////////////

#endif
